﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace DataService.Core.DataHelper
{
    /// <summary>随机数</summary>
    public static class RandHelper
    {
#if NETCOREAPP || NETSTANDARD2_1_OR_GREATER
    /// <summary>返回一个小于所指定最大值的非负随机数</summary>
    /// <param name="max">返回的随机数的上界（随机数不能取该上界值）</param>
    /// <returns></returns>
    public static Int32 Next(Int32 max = Int32.MaxValue) => RandomNumberGenerator.GetInt32(max);

    /// <summary>返回一个指定范围内的随机数</summary>
    /// <remarks>
    /// 调用平均耗时37.76ns，其中GC耗时77.56%
    /// </remarks>
    /// <param name="min">返回的随机数的下界（随机数可取该下界值）</param>
    /// <param name="max">返回的随机数的上界（随机数不能取该上界值）</param>
    /// <returns></returns>
    public static Int32 Next(Int32 min, Int32 max) => RandomNumberGenerator.GetInt32(min, max);
#else
        private static readonly RandomNumberGenerator _rnd;

        static RandHelper() => _rnd = new RNGCryptoServiceProvider();

        /// <summary>返回一个小于所指定最大值的非负随机数</summary>
        /// <param name="max">返回的随机数的上界（随机数不能取该上界值）</param>
        /// <returns></returns>
        public static Int32 Next(Int32 max = Int32.MaxValue)
        {
            if (max <= 0) throw new ArgumentOutOfRangeException(nameof(max));

            return Next(0, max);
        }

        [ThreadStatic]
        private static Byte[]? _buf;
        /// <summary>返回一个指定范围内的随机数</summary>
        /// <remarks>
        /// 调用平均耗时37.76ns，其中GC耗时77.56%
        /// </remarks>
        /// <param name="min">返回的随机数的下界（随机数可取该下界值）</param>
        /// <param name="max">返回的随机数的上界（随机数不能取该上界值）</param>
        /// <returns></returns>
        public static Int32 Next(Int32 min, Int32 max)
        {
            if (max <= min) throw new ArgumentOutOfRangeException(nameof(max));

            _buf ??= new Byte[4];
            _rnd.GetBytes(_buf);

            var n = BitConverter.ToInt32(_buf, 0);
            if (min == Int32.MinValue && max == Int32.MaxValue) return n;
            if (min == 0 && max == Int32.MaxValue) return Math.Abs(n);
            if (min == Int32.MinValue && max == 0) return -Math.Abs(n);

            var num = max - min;
            // 不要进行复杂运算，看做是生成从0到(max-min)的随机数，然后再加上min即可
            return (Int32)((num * (UInt32)n >> 32) + min);
        }
#endif

        /// <summary>返回指定长度随机字节数组</summary>
        /// <remarks>
        /// 调用平均耗时5.46ns，其中GC耗时15%
        /// </remarks>
        /// <param name="count"></param>
        /// <returns></returns>
        public static Byte[] NextBytes(Int32 count)
        {
#if NET6_0_OR_GREATER
        return RandomNumberGenerator.GetBytes(count);
#elif NETFRAMEWORK || NETSTANDARD2_0
            return new Random().NextBytes(count);
#else
        var buf = new Byte[count];
        RandomNumberGenerator.Fill(buf);
        return buf;
#endif
        }

#if NETFRAMEWORK || NETSTANDARD2_0
        /// <summary>
        /// 返回随机数填充的指定长度的数组
        /// </summary>
        /// <param name="random"></param>
        /// <param name="length">数组长度</param>
        /// <returns>随机数填充的指定长度的数组</returns>
        private static Byte[] NextBytes(this Random random, Int32 length)
        {
            if (length < 0) throw new ArgumentOutOfRangeException(nameof(length));

            var data = new Byte[length];
            random.NextBytes(data);
            return data;
        }
#endif



        /// <summary>返回指定长度随机字符串</summary>
        /// <param name="length">长度</param>
        /// <param name="symbol">是否包含符号</param>
        /// <returns></returns>
        public static String NextString(Int32 length,bool symbol=false)
        {
            //string allChar = "0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,W,X,Y,Z,q,w,e,r,t,y,u,i,o,p,a,s,d,f,g,h,j,k,l,z,x,c,v,b,n,m,!,@,#,$,%,^,&,*";
            //string[] allCharArray = allChar.Split(',');
            //string randomCode = "";
            //int temp = -1;
            //Random random = new Random();
            //for (int i = 0; i < length; i++)
            //{
            //    if (temp != -1)
            //    {
            //        random = new Random(i * temp * (int)DateTime.Now.Ticks);
            //    }
            //    int t = random.Next(68);
            //    if (temp == t)
            //    {
            //        return NextString(length);
            //    }
            //    temp = t;
            //    randomCode += allCharArray[temp];
            //}
            //return randomCode;


            var sb = new StringBuilder();
            for (var i = 0; i < length; i++)
            {
                var ch = ' ';
                if (symbol)
                {
                    ch = (Char)Next(' ', 0x7F);
                }
                else
                {
                    var n = Next(0, 10 + 26 + 26);
                    if (n < 10)
                        ch = (Char)('0' + n);
                    else if (n < 10 + 26)
                        ch = (Char)('A' + n - 10);
                    else
                        ch = (Char)('a' + n - 10 - 26);
                }
                sb.Append(ch);
            }
            return sb.ToString();

        }
    }
}
